﻿namespace VirtualTemplates
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Hosting;

    /// <summary>
    /// Ensures that requests with specific file extensions are handled by ASP.NET.
    /// </summary>
    public class HandleVirtualFileModule : IHttpModule
    {
        private static readonly VirtualFileHandler VirtualFileHandler;

        private static ISet<string> fileExtensions;

        /// <summary>
        /// Initializes static members of the <see cref="HandleVirtualFileModule"/> class.
        /// </summary>
        static HandleVirtualFileModule()
        {
            VirtualFileHandler = new VirtualFileHandler();
        }

        /// <summary>
        /// Gets the http cache policy for virtual files.
        /// </summary>
        public static VirtualFileCachePolicy Cache
        {
            get { return VirtualFileHandler.Cache; }
        }

        /// <summary>
        /// Gets the file extensions of the files that should be handled as virtual files.
        /// </summary>
        public static ISet<string> FileExtensions
        {
            get { return fileExtensions ?? (fileExtensions = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)); }
        }

        /// <summary>
        /// Inits the specified application.
        /// </summary>
        /// <param name="application">The application.</param>
        public void Init(HttpApplication application)
        {
            application.BeginRequest += application_BeginRequest;

            application.PostResolveRequestCache += OnPostResolveRequestCache;
        }

        void application_BeginRequest(object sender, EventArgs e)
        {
            
        }

        /// <summary>
        /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
        /// </summary>
        public void Dispose()
        {
        }

        /// <summary>
        /// Called before handler mapping in the execution pipeline.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private static void OnPostResolveRequestCache(object sender, EventArgs e)
        {
            var httpContext = ((HttpApplication)sender).Context;

            if (ShouldRemapFor(httpContext.Request))
            {
                new HttpContextWrapper(httpContext).RemapHandler(VirtualFileHandler);
            }
        }

        /// <summary>
        /// Determines wether the virtual file handler should be used for the specified path.
        /// </summary>
        /// <param name="httpRequest">The http request.</param>
        /// <returns>
        /// true if the virtual file handler should be used, otherwise false.
        /// </returns>
        private static bool ShouldRemapFor(HttpRequest httpRequest)
        {
            var virtualPath = httpRequest.CurrentExecutionFilePath;

            return !File.Exists(httpRequest.PhysicalPath) && FileExtensions.Any(e => virtualPath.EndsWith(e, StringComparison.InvariantCultureIgnoreCase))
                && HostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
        }
    }
}
